#include "threadPool.h"

int recvn(int netfd, void *buf, int length){
    int total = 0;
    int ret;
    char *p = (char *)buf;
    while(total < length){
        ret = recv(netfd,p + total,length - total,0);
        if(ret == 0)// 进来说明没收完，没收完返回值却是0则说明对面断开了，可以退出
        {
            return 0;
        }
        total += ret;
    }
    return 0;
}

int recvFile(int netfd, int user_id){
    //接收到文件名
    train_t train;
    bzero(&train,sizeof(train_t));
    char file_name[1024] = {0};
    recv(netfd,&train.length,sizeof(train.length),MSG_WAITALL);
    //printf("train.length = %d\n",train.length);
    if(train.length == 0){
        return -1;//对方文件打开失败
    }
    recvn(netfd,train.data,train.length);
    memcpy(file_name,train.data,train.length);
    //printf("file_name is %s\n",file_name);
    //接收原文件大小
    off_t fileSize;
    bzero(&train,sizeof(train_t));
    recvn(netfd,&train.length,sizeof(int));
    recvn(netfd,train.data,train.length);
    memcpy(&fileSize,train.data,train.length);
    printf("fileSize = %ld\n",fileSize);
    //接收md5值
    char md5_str[MD5_STR_LEN + 1] = {0};
    bzero(&train,sizeof(train_t));
    recvn(netfd,&train.length,sizeof(int));
    recvn(netfd,train.data,train.length);
    memcpy(md5_str,train.data,train.length);
    //printf("md5 = %s\n",md5_str);
    //通过user_id获取当前目录的code，以作为file的parent_id
    int code;
    get_user_code(user_id,&code);
    //检查fsystem中是否已有该文件
    int Ret = get_fsystem_md5(file_name,user_id,code,md5_str);
    if(Ret == -1){//文件不存在，则插入fsystem中
        add_fsystem_file(code,file_name,user_id,md5_str,fileSize);
    }
    //检查该文件是否已存在于本地文件表
    int ret = if_local_exist(md5_str);
    char real_file_name[1024] = {0};
    char path[1024] = {0};
    int fd;
    off_t exitSize = 0;
    int check = 0;
    if(ret == 0){//文件已存在
        //查询文件本地真实名，并打开得到已传大小
        get_real_file_name(md5_str,real_file_name);
        sprintf(path,"Netdisk/%s",real_file_name);
        fd = open(path,O_RDWR|O_CREAT,0666);//考虑文件被误删，未更新本地文件表的情况
        LOG_ERROR(fd,-1,"open");
        struct stat stat_buf;
        int rret = fstat(fd,&stat_buf);
        LOG_ERROR(rret,-1,"fstat");
        exitSize = stat_buf.st_size;
        if(exitSize < fileSize){//通知客户端需要上传
            check = 1;
            send(netfd,&check,sizeof(int),MSG_NOSIGNAL);
        }
        else{//一键秒传
            send(netfd,&check,sizeof(int),MSG_NOSIGNAL);
            if(Ret == -1){//若文件原先不存在于fsystem，则增加链接数
                add_link(md5_str);
            }
            return 0;
        }
    }
    else{//文件不存在,通知客户端文件需要上传,且下载文件并添加到本地文件表中
        check = 1;
        send(netfd,&check,sizeof(int),MSG_NOSIGNAL); 
        //拼接出一个本地文件名，用文件名、user_id和当前目录id，这样不同用户的同名文件，或同一用户不同文件夹中的同名文件，就不会在本地重名了
        bzero(path, sizeof(path));
        sprintf(real_file_name, "%s%d%d", file_name, user_id, code);
        add_local_file(md5_str, real_file_name);
        sprintf(path, "%s%s%s", "Netdisk", "/", real_file_name);
        fd = open(path, O_RDWR | O_CREAT, 0666); // 文件不存在就创建
        LOG_ERROR(fd, -1, "open");
        //获取文件大小，这里肯定不存在，只是为了客户端不阻塞
        struct stat statbuf;
        ret = fstat(fd, &statbuf);
        LOG_ERROR(ret, -1, "fstat");
        exitSize = statbuf.st_size;
    }
    //发送接收文件大小
    printf("exitSize = %ld\n",exitSize);
    send(netfd,&exitSize,sizeof(off_t),MSG_NOSIGNAL);
    lseek(fd,0,SEEK_END);

    if(fileSize >= 1073741824){// 大于1G,一次性接收
        ftruncate(fd,fileSize);
        char *p = (char *)mmap(NULL,fileSize,PROT_WRITE|PROT_READ,MAP_SHARED,fd,0);
        LOG_ERROR(p,MAP_FAILED,"mmap");
        recvn(netfd,p,fileSize);
        munmap(p,fileSize);
    }

    else{//分批接收
    long curSize = exitSize;
    long lastSize = exitSize;
    long slice = fileSize / 1000;
    while(1){
        bzero(&train,sizeof(train));
        ret = recv(netfd,&train.length,sizeof(train.length),MSG_WAITALL);
        //recvn(netfd,&train.length,sizeof(int));
        if(train.length == 0 && ret != 0){//length为0说明传输完成
            printf("file is recived!\n");
            break;
        }
        if(ret == 0){//说明对面提前断开
            close(fd);
            return -1;
        }
        recv(netfd,train.data,train.length,MSG_WAITALL);
        //recvn(netfd,train.data,train.length);
        write(fd,train.data,train.length);
        curSize += train.length;
        if(curSize < fileSize){
            if(curSize - lastSize > slice){
                printf("%5.2lf%%\r",100.0*curSize/fileSize);
                fflush(stdout);
                lastSize = curSize;
            }
        }
    }
    printf("100.00%%\n");
    }
    close(fd);
    return 0;
}